import json
import traceback
import threading
import serial
import serial.tools.list_ports
import time


class DTUManager:
    SUCCESS = "获取成功"
    FAIL = "获取失败"

    EN_TO_CHINESE = {
        "Online": "在线",
        "Offline": "离线",
        "Connected": "已连接",
        "NotConnected": "未连接",
        "socket1_off": "单通道",
        "socket1_mult": "双通道",
        "socket1_back": "主备",
        0: "正常",
        1: "性能优先",
        2: "平衡",
        "tcp_client": "TCP Client",
        "tcp_server": "TCP Server",
        "udp": "UDP",
    }

    CH_TO_ENGLISH = {v: k for k, v in EN_TO_CHINESE.items()}

    def __init__(self, port='COM3', baudrate=115200, timeout=1):
        self.port = port
        self.baudrate = baudrate
        self.timeout = timeout
        self.ser = None
        self.PROCESS_RESPONSE_DICT = {
            "sta_read": self._process_response_sta_read,
            "dtu_read": self._process_response_dtu_read,
            "socket_read": self._process_response_socket_read,
            "socket1_read": self._process_response_socket_read,
            "sim_read": self._process_response_sim_read,
            "sys_read": self._process_response_sys_read,
        }

    def send_command(self, command):

        try:
            if not self.ser or not self.ser.isOpen():
                self.ser = serial.Serial(
                    port=self.port,
                    baudrate=self.baudrate,
                    timeout=self.timeout
                )
                print(f"Connected to {self.port}")
            # 尝试写入命令
            thread = threading.Thread(target=self.write_to_serial_thread, args=(command,))
            thread.start()

            time.sleep(0.5)

            # 读取响应
            response = self.ser.read_all().decode()
            print(f"Response: {response}")
            if '>' in response:
                return response
            #     json_response = response.split('>')[1]
            #     final_response = json.loads(json_response)
            #     return final_response
            else:
                final_response = {"dtu_msg": "fail", "value": "未接收到有效响应"}
                return final_response

        except Exception as e:
            print(e, traceback.format_exc())
            print(f"Error: {e}")

            # 最后一次重试仍然失败
            real_error = "错误信息"
            if "list index out of range" in str(e):
                real_error = "指令异常，无法识别的指令，确认设备是否开启！"
            elif "could not open port" in str(e):
                real_error = "串口异常，串口被占用或者未启用！"
            final_response = {"dtu_msg": "fail", "value": f"{real_error}:{e}"}

        finally:
            if self.ser:
                self.ser.close()

        return final_response


    def write_to_serial_thread(self, command):
        try:
            self.ser.write(command.encode())
            # 如果需要，可以添加等待响应的代码
            # ...
        except serial.SerialException as e:
            print(f"Error in serial thread: {e}")

    def splicing_instruction(self, cmd, value=None):
        cmd_dict = {"dtu_msg": cmd}
        if isinstance(value, dict):
            for k, v in value.items():
                if v in self.CH_TO_ENGLISH:
                    value[k] = self.CH_TO_ENGLISH[v]
        if value is not None:
            cmd_dict["value"] = value
        cmd_json = json.dumps(cmd_dict)
        return f"DTU>{cmd_json}\r\n"


    def get_data(self, cmd, value=None):

        command = self.splicing_instruction(cmd, value)
        print(command)
        res = self.send_command(command)
        if cmd in self.PROCESS_RESPONSE_DICT:
            processor = self.PROCESS_RESPONSE_DICT.get(cmd)
            return processor(res)

        return res

    def get_custom_data(self, command):
        print(command)
        res = self.send_command(command)
        print(res)
        print(type(res))
        return json.dumps(res, indent=4, ensure_ascii=False)

    @classmethod
    def detect_serial_ports(cls):
        return list(serial.tools.list_ports.comports())

    def _process_response_sta_read(self, res):
        if res.get("dtu_msg") != "ok":
            return {
                "network_status": self.FAIL,
                "socket_status": self.FAIL,
                "socket1_status": self.FAIL,
                "csq": self.FAIL,
                "rssi": self.FAIL,
                "snr": self.FAIL,
                "error_info": res.get("value")
            }
        values = res.get("value").split(",")
        return {
            "network_status": self.EN_TO_CHINESE.get(values[0]),
            "socket_status": self.EN_TO_CHINESE.get(values[1]),
            "socket1_status": self.EN_TO_CHINESE.get(values[2]),
            "csq": values[3].split(":")[1],
            "rssi": values[4].split(":")[1],
            "snr": values[5].split(":")[1],
            "error_info": self.SUCCESS
        }

    def _process_response_dtu_read(self, res):
        if res.get("dtu_msg") != "ok":
            return {
                "apn": self.FAIL,
                "apn_password": self.FAIL,
                "revtime": '0',
                "mode": self.FAIL,
                "uart485": self.FAIL,
                "apn_user": self.FAIL,
                "uartbps": '0',
                "lprun": '0',
                "error_info": res.get("value"),
            }
        return {
            "apn": res.get("value", {}).get("apn", "- -"),
            "apn_password": res.get("value", {}).get("apn_password", "- -"),
            "revtime": str(res.get("value", {}).get("revtime")),
            "mode": self.EN_TO_CHINESE.get(res.get("value", {}).get("mode")),
            "uart485": res.get("value", {}).get("uart485"),
            "apn_user": res.get("value", {}).get("apn_user", "- -"),
            "uartbps": res.get("value", {}).get("uartbps"),
            "lprun": self.EN_TO_CHINESE.get(res.get("value", {}).get("lprun")),
            "error_info": self.SUCCESS,
        }

    def _process_response_dtu_write(self, res):
        if res.get("dtu_msg") != "ok":
            return {
                "apn": self.FAIL,
                "apn_password": self.FAIL,
                "revtime": self.FAIL,
                "mode": self.FAIL,
                "uart485": self.FAIL,
                "apn_user": self.FAIL,
                "uartbps": self.FAIL,
                "lprun": self.FAIL,
                "error_info": res.get("value"),
            }
        return {
            "apn": res.get("value", {}).get("apn", "- -"),
            "apn_password": res.get("value", {}).get("apn_password", "- -"),
            "revtime": str(res.get("value", {}).get("revtime")),
            "mode": self.EN_TO_CHINESE.get(res.get("value", {}).get("mode")),
            "uart485": res.get("value", {}).get("uart485"),
            "apn_user": res.get("value", {}).get("apn_user", "- -"),
            "uartbps": res.get("value", {}).get("uartbps"),
            "lprun": self.EN_TO_CHINESE.get(res.get("value", {}).get("lprun")),
            "error_info": self.SUCCESS,
        }

    def _process_response_socket_read(self, res):
        if res.get("dtu_msg") != "ok":
            return {
                "register": self.FAIL,
                "heartbeat": self.FAIL,
                "host": self.FAIL,
                "heartbeat_time": '0',
                "port": '0',
                "type": self.FAIL,
                "timeout": '- -',
                "error_info": res.get("value")
            }
        return {
            "register": res.get("value", {}).get("register"),
            "heartbeat": res.get("value", {}).get("heartbeat"),
            "host": res.get("value", {}).get("host"),
            "heartbeat_time": str(res.get("value", {}).get("heartbeat_time")),
            "port": str(res.get("value", {}).get("port")),
            "type": self.EN_TO_CHINESE.get(res.get("value", {}).get("type")),
            "timeout": "- -",
            "error_info": self.SUCCESS
        }

    def _process_response_sim_read(self, res):
        if res.get("dtu_msg") != "ok":
            return {
                "id": self.FAIL,
                "imsi": self.FAIL,
                "iccid": self.FAIL,
                "error_info": res.get("value")
            }
        if res.get("value") is not None:
            values = res.get("value").split(",")
            return {
                "id": values[0].split(":")[1],
                "imsi": values[1].split(":")[1],
                "iccid": values[2].split(":")[1],
                "error_info": self.SUCCESS
            }

    def _process_response_sys_read(self, res):
        if res.get("dtu_msg") != "ok":
            data = {
                "version": self.FAIL,
                "imei": self.FAIL,
                "error_info": res.get("value")
            }
            return data

        if res.get("value") is not None:
            values = res.get("value").split(",")
            data = {
                "version": f"{values[0]},{values[1]}",
                "imei": values[2].split(":")[1],
                "error_info": self.SUCCESS
            }
            return data


if __name__ == '__main__':
    manager = DTUManager(port='COM4')
    command = "AT+CMD"
    response = manager.send_command(command)
    print(f"Final Response: {response}")
